package com.io.utils.shiro;

import com.google.common.base.Strings;
import com.io.dto.ApiResult;
import com.io.entity.SysUserEntity;
import com.io.exception.SelfException;
import com.io.service.SysMenuService;
import com.io.service.SysRoleService;
import com.io.service.SysUserService;
import com.io.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Set;

/**
 * The class/interface 认证
 *
 * @author guod
 * @version 1.0 use jdk 1.8
 */
@Slf4j
@Component
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SysUserService userService;

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysMenuService menuService;

    /**
     * 必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 用户身份识别(登录")
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        // 校验token有效性
        ApiResult info = JwtUtil.getUsername(token);
        String username = (String) info.get("message");
        if (Strings.isNullOrEmpty(username)) {
            throw new SelfException("token非法无效!");
        }
        // 查询用户信息
        SysUserEntity sysUser = userService.selectByUsername(username);
        if (StringUtils.isEmpty(sysUser)) {
            throw new SelfException("用户不存在!");
        }
        // 判断用户状态
        return new SimpleAuthenticationInfo(sysUser, token, ByteSource.Util.bytes(sysUser.getSalt()), getName());
    }

    /**
     * 访问控制。比如某个用户是否具有某个操作的使用权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        SysUserEntity user = (SysUserEntity) principalCollection.getPrimaryPrincipal();
        if (user == null) {
            log.error("授权失败，用户信息为空！");
            return null;
        }
        try {
            // 获取用户角色ID集
            Set<String> listRole = roleService.findRoleByUsername(user.getUsername());
            simpleAuthorizationInfo.addRoles(listRole);
            // 通过角色ID获取权限集
            for (String role : listRole) {
                Set<String> permission = menuService.findPermissionByRole(role);
                simpleAuthorizationInfo.addStringPermissions(permission);
            }
            return simpleAuthorizationInfo;
        } catch (Exception e) {
            log.error("授权失败，请检查系统内部错误！", e);
        }
        return simpleAuthorizationInfo;
    }
}
